﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace fhe
{
  namespace core
  {
    public class Node
    {
      public List<Node> Children { get; set; }

      public Node()
      {
        Children = new List<Node>();
      }

      public void Publish<T>(Action<T> f, Action<T> outf = null) where T : class
      {
        if (this is T)
        {
          f(this as T);
        }
        Children.ForEach(child => child.Publish(f, outf));
        if (outf != null && this is T)
        {
          outf(this as T);
        }
      }

      public List<R> Publish<T, R>(Func<T, R> f, Func<T, R> outf = null) where T : class
      {
        List<R> r = new List<R>();
        if (this is T)
        {
          r.Add(f(this as T));
        }
        r.AddRange(Children.SelectMany(child => child.Publish(f, outf)));
        if (outf != null && this is T)
        {
          r.Add(outf(this as T));
        }
        return r;
      }

      public List<T> GetDescendantsOfType<T>() where T : class
      {
        List<T> l = new List<T>();
        if (this is T)
        {
          l.Add(this as T);
        }
        l.AddRange(Children.SelectMany(child => child.GetDescendantsOfType<T>()));
        return l;
      }
    }
  }
}
